<?php
require_once ROOT_PATH.'boot/req_inc.php';

abstract class Cache implements ICache{
	public		$default_ttl=300;	//default ttl,$ttl==NULL , use the value
	function __construct(){
		$t=$GLOBALS['context']->get_app_conf('default_ttl');
		if($t) $this->default_ttl=$t;
	}
}

class EmptyCache extends Cache implements IRequestTool{
	static function register($prop){
		//$GLOBALS['context']->log_debug('EmptyCache create');
		return new EmptyCache();
	}
	function 	get($key){ return NULL;}
	function 	set($key,$value,$ttl=NULL){}
	function 	delete($key){}
	function 	clear(){}
}
class FileCache  extends Cache implements IRequestTool{
	private $cache='cache/data';
	private $cache_path;
	private $enable=false;
	static private $level=1;
	function __construct(){
		parent::__construct();
		$this->cache_path=ROOT_PATH."{$GLOBALS['context']->app_name}/{$this->cache}/";
		if(! @file_exists($this->cache_path)){
			//$GLOBALS['context']->log_debug('mkdir data cache :'.$this->cache_path);
			mkdir($this->cache_path,0777,true);
		}
		$this->enable=@file_exists($this->cache_path);
	}
	static function register($prop){
		//$GLOBALS['context']->log_debug('FileCache create');
		self::$level = $prop?$prop:1;
		return new FileCache();
	}
	function	set_path($cache){
		$this->cache_path = ROOT_PATH."{$GLOBALS['context']->app_name}/{$cache}/";
	}
	function 	get($key, $flag=true, $path=''){
		if(! $this->enable) return NULL;
		if($flag){
			$file_path=$this->cache_path.$key.'.php';
			if(DS==='\\') $file_path=str_replace('/',DS,$file_path);
			if(! @file_exists($file_path)) return NULL;

			$data=NULL;
			$_the_file_ttl=NULL;
			if(@file_exists($file_path) && is_dir($file_path)) {
				include_once($file_path);
			}
//			include $file_path;
			if($data!==NULL && $_the_file_ttl && $_the_file_ttl>time() )  {
				return $data;
			}
		}else{
			$this->set_path($path);
			$file_path=$this->cache_path.$key;
			if(! @file_exists($file_path)) return NULL;
			$_the_file_ttl = NULL;
			$data = file_get_contents($file_path);
			preg_match("/(?<=\<\!--\{\[)\d+(?=\]\}-->)/i", $data, $ttl);
			if(isset($ttl[0])){
				$_the_file_ttl = intval($ttl[0]);
			}
			if($data!='' && $_the_file_ttl && $_the_file_ttl>time() )  {
				return $data;
			}
		}
		if(@file_exists($file_path))	@unlink($file_path);
		return NULL;
	}
	/**
	 * 文件缓存中的值

	 * @param $key cooki的命名

	 * @param $value cookie的值

	 * @param $ttl 时间
	 * @param $sql 缓存时执行的sql文件
	 * @param $sql_values  sql中的值

	 */
	function 	set($key, $value, $ttl=NULL, $sql=NULL, $sql_values=NULL){
		if(! $this->enable) return false;
		if(! $ttl) $ttl=$this->default_ttl;
		$rpos=strrpos($key,'/');
		if($rpos!==false){
			$key_path=$this->cache_path.substr($key,0,$rpos);
			if(! @file_exists($key_path)){
				//$GLOBALS['context']->log_debug('mkdir data cache :'.$key_path);
				mkdir($key_path,0777,true);
			}
		}
		if($sql === false){
			$file_path=$this->cache_path.$key;
			$lines = $value . "\n<!--{[". ($ttl*self::$level+time()) ."]}-->\n";
		}else{
			$file_path=$this->cache_path.$key.'.php';

			$lines="<?php \n if (!defined('ROOT_PATH')) die('401,未授权访问 [Unauthorized]');\n";
			$lines = $lines . '$data='.var_export($value,true).";\n";
			$lines .= '$_the_file_ttl='. ($ttl*self::$level+time()) .";\n";
			$lines .= '$_write_time='. time() .";\n";
			if($sql) $lines .='$sql='.var_export($sql, true).";\n";
			if($sql_values) $lines .='$_sql_values='.var_export($sql_values, true).";\n";
		}
		@file_put_contents($file_path,$lines);

		return true;
	}
	function 	delete($key){
		if(! $this->enable) return false;
		$file_path=$this->cache_path.$key.'.php';
		clearstatcache();
		if(@file_exists($file_path))	@unlink($file_path);
	}
	function 	clear(){
		if(! $this->enable) return false;
		require_lib('util/file_util',true);
		@rmdir_r($this->cache_path);
	}
}


class ApcCache  extends Cache implements IRequestTool{
	private $enable=false;
	static private $level=1;
	function __construct(){
		$this->enable=extension_loaded('apc');
		parent::__construct();
	}
	static function register($prop){
		self::$level = $prop?$prop:1;
		if(extension_loaded('apc')){
			//$GLOBALS['context']->log_debug('ApcCache create');
			return new ApcCache();
		}
		else return FileCache::register($prop);
	}
	function 	get($key){
		if(! $this->enable) return NULL;
		$exists=false;
		$data=apc_fetch($key,$exists);
		if(! $exists)	return NULL;
		else return $data;
	}
	function 	set($key,$value,$ttl=NULL){
		if(! $this->enable) return false;
		if(! $ttl) $ttl=$this->default_ttl;
		apc_store($key,$value,$ttl*self::$level);
	}
	function 	delete($key){
		if(! $this->enable) return false;
		apc_delete($key);
	}
	function 	clear(){
		if(! $this->enable) return false;
		apc_clear_cache('user');
	}
}

class MemCacheCache  extends Cache implements IRequestTool{
	private $enable=false;
	private $memcache=NULL;
	static private $level=1;
	function __construct(){
		$this->enable=extension_loaded('memcache');
		parent::__construct();
	}
	static function register($prop){
		self::$level = $prop?$prop:1;
		if(extension_loaded('memcache')){
			//$GLOBALS['context']->log_debug('MemCacheCache create');
			return new MemCacheCache();
		}
		else return FileCache::register($prop);
	}
	function get_cache(){
		if($this->enable && $this->memcache===NULL){
			$app_conf_memcache_host=$GLOBALS['context']->get_app_conf('memcache_host');
			if(! $app_conf_memcache_host)	return;
			//$GLOBALS['context']->log_debug('MemCacheCache connect');
			$this->memcache=new Memcache();
			foreach($app_conf_memcache_host as $host)
				$this->memcache->addServer($host);
			return $this->memcache;
		}
	}
	function 	get($key){
		$this->get_cache();
		if($this->memcache===NULL) return NULL;
		$val=$this->memcache->get($key);
		return $val===FALSE? NULL : $val;
	}
	function 	set($key,$value,$ttl=NULL){
		$this->get_cache();
		if($this->memcache===NULL) return false;
		if($value===FALSE) $value=0;
		if(! $ttl) $ttl=$this->default_ttl;
		return $this->memcache->set($key,$value,0,$ttl*self::$level);
	}
	function 	delete($key){
		$this->get_cache();
		if($this->memcache===NULL) return false;
		$this->memcache->delete($key);
	}
	function 	clear(){
		$this->get_cache();
		if($this->memcache===NULL) return false;
		$this->memcache->flush();
	}
}